package com.zxx.flowerstore.utils.utils;

import com.zxx.flowerstore.entity.enums.ResultEnum;
import com.zxx.flowerstore.utils.common.MyException;
import org.apache.commons.lang3.StringUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @ClassName ListUtils
 * @Author Admin
 * @Date 2021/3/20 11:43
 * @Description ListUtils
 * @Version 1.0
 */
public class ListUtils {

    private static final String DEFAULT_DELIMITER = ",";
    private static final int DEFAULT_PAGE_SIZE = 1000;

    private ListUtils() {
    }

    /**
     * 汇总/求和
     *
     * @param list
     * @param mapper
     * @return: java.math.BigDecimal
     * @author: zhengxin
     * @date: 2020/7/14 11:02
     * @version: 1.0
     */
    public static <T, R> BigDecimal summing(List<T> list, Function<T, R> mapper) {
        if (Objects.isNull(list) || list.size() == 0) {
            return BigDecimal.ZERO;
        }

        Objects.requireNonNull(mapper);

        BigDecimal reduce = list.stream()
                .map(mapper)
                .map(DecimalUtil::toDecimal)
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        return reduce;
    }

    public static <T> Float summingFloat(List<T> list, Function<T, Float> mapper) {
        return summingDouble(list, t -> mapper.apply(t).doubleValue()).floatValue();
    }

    public static <T> Double summingDouble(List<T> list, Function<T, Double> mapper) {
        if (Objects.isNull(list) || list.size() == 0) {
            return 0.0;
        }

        Objects.requireNonNull(mapper);
        Double res = list.stream()
                .map(mapper)
                .collect(Collectors.summingDouble(Double::doubleValue));
        return res;
    }

    /**
     * 汇总/求和
     *
     * @param list
     * @param calculation
     * @param mapper1
     * @param mapper2
     * @return java.math.BigDecimal
     * @author zhengxin
     * @date 2020/7/28 10:44
     * @version: 1.0
     */
    public static <T, R> BigDecimal summing(List<T> list, BiFunction<BigDecimal, BigDecimal, BigDecimal> calculation,
                                            Function<T, R> mapper1, Function<T, R> mapper2) {
        if (Objects.isNull(list) || list.size() == 0) {
            return BigDecimal.ZERO;
        }

        BigDecimal reduce = list.stream()
                .map(item -> calculation.apply(DecimalUtil.toDecimal(mapper1.apply(item)),
                        DecimalUtil.toDecimal(mapper2.apply(item))))
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        return reduce;
    }

    /**
     * 字段去重收集
     *
     * @param list
     * @param functions
     * @return java.util.List<R>
     * @author zhengxin
     * @date 2020/7/29 14:36
     * @version: 1.0
     */
    public static <T, R> List<R> map(List<T> list, Function<T, R>... functions) {
        if (Objects.isNull(list) || list.size() == 0) {
            return Collections.emptyList();
        }

        List<R> collect = list.stream()
                .map(item -> Stream.of(functions)
                        .map(getter -> getter.apply(item))
                        .collect(Collectors.toList()))
                .flatMap(Collection::stream)
                .filter(Objects::nonNull)
                .filter(item -> StringUtils.isNotBlank(String.valueOf(item)))
                .distinct()
                .collect(Collectors.toList());

        return collect;
    }

    /**
     * 将对象数组转为该对象关联数组的合集（二维数组转一维数组）
     *
     * @param list   待转换对象数组
     * @param mapper 对象关联数组getter方法
     * @return java.util.List<R>
     * @author zhengxin
     * @date 2020/8/10 16:16
     * @version: 1.0
     */
    public static <T, R> List<R> flatMap(List<T> list, Function<T, List<R>> mapper) {
        if (Objects.isNull(list) || list.size() == 0) {
            return Collections.emptyList();
        }

        List<R> collect = list.stream()
                .map(mapper)
                .filter(item -> !Objects.isNull(item))
                .flatMap(Collection::stream)
                .collect(Collectors.toList());

        return collect;
    }

    /**
     * 字符串拼接
     *
     * @param list
     * @param mapper
     * @return: java.lang.String
     * @author: zhengxin
     * @date: 2020/7/14 11:23
     * @version: 1.0
     */
    public static <T, R> String joining(List<T> list, Function<T, R> mapper) {
        return joining(list, mapper, DEFAULT_DELIMITER);
    }

    /**
     * 字符串拼接
     *
     * @param list      数据源List
     * @param mapper    获取对象数据方法
     * @param delimiter 分隔符
     * @return java.lang.String
     * @author zhengxin
     * @date 2020/8/7 9:13
     * @version: 1.0
     */
    public static <T, R> String joining(List<T> list, Function<T, R> mapper, String delimiter) {
        if (Objects.isNull(list) || list.size() == 0) {
            return null;
        }

        String collect = list.stream()
                .map(mapper)
                .filter(Objects::nonNull)
                .map(String::valueOf)
                .collect(Collectors.joining(delimiter));

        return collect;
    }

    /**
     * 字符串拼接
     *
     * @param list
     * @param mapper
     * @return: java.lang.String
     * @author: zhengxin
     * @date: 2020/7/14 11:29
     * @version: 1.0
     */
    public static <T, R> String distinctJoining(List<T> list, Function<T, R> mapper) {
        return distinctJoining(list, mapper, DEFAULT_DELIMITER);
    }

    /**
     * 字符串拼接
     *
     * @param list      数据源List
     * @param mapper    获取对象数据方法
     * @param delimiter 分隔符
     * @return java.lang.String
     * @author zhengxin
     * @date 2020/8/7 9:14
     * @version: 1.0
     */
    public static <T, R> String distinctJoining(List<T> list, Function<T, R> mapper, String delimiter) {
        if (Objects.isNull(list) || list.size() == 0) {
            return null;
        }

        String collect = list.stream()
                .map(mapper)
                .filter(Objects::nonNull)
                .map(String::valueOf)
                .filter(StringUtils::isNotBlank)
                .distinct()
                .collect(Collectors.joining(","));

        return collect;
    }

    /**
     * List集合去重
     *
     * @param list      待去重List集合
     * @param functions 去重属性getter
     * @return java.util.List<T>
     * @author zhengxin
     * @date 2020/8/10 16:02
     * @version: 1.0
     */
    public static <T, R> List<T> distinct(List<T> list, Function<T, R>... functions) {

        Collection<T> values = list.stream()
                .collect(Collectors.toMap(item -> Stream.of(functions)
                                .map(getter -> getter.apply(item))
                                .map(ListUtils::defaultIfBlank)
                                .collect(Collectors.joining(DEFAULT_DELIMITER)),
                        Function.identity(),
                        (old, cur) -> old)).values();

        return new ArrayList<>(values);
    }

    /**
     * 为空返回默认空串
     *
     * @param object
     * @return java.lang.String
     * @author zhengxin
     * @date 2020/8/10 16:00
     * @version: 1.0
     */
    private static String defaultIfBlank(Object object) {
        if (Objects.isNull(object)) {
            return StringUtils.EMPTY;
        }
        return StringUtils.defaultIfBlank(object.toString(), StringUtils.EMPTY);
    }

    /**
     * 根据指定长度切分数组
     *
     * @param list
     * @return java.util.List<java.util.List < E>>
     * @author zhengxin
     * @date 2020/8/7 10:25
     * @version: 1.0
     */
    public static <E> List<List<E>> split(List<E> list) {
        return split(list, DEFAULT_PAGE_SIZE);
    }

    /**
     * 根据指定长度切分数组
     *
     * @param list     待切分数组
     * @param pageSize 切分后数组长度
     * @return java.util.List<java.util.List < E>>
     * @author zhengxin
     * @date 2020/8/7 10:23
     * @version: 1.0
     */
    public static <E> List<List<E>> split(List<E> list, int pageSize) {
        if (list == null) {
            throw new MyException(ResultEnum.ERROR.getCode(), "切分List失败！list为NULL");
        }
        if (pageSize < 1) {
            throw new MyException(ResultEnum.ERROR.getCode(), "切分List失败！length不能小于1");
        }
        int size = list.size();
        int pageCount = size % pageSize == 0 ? size / pageSize : size / pageSize + 1;

        return Stream.iterate(0, n -> n + 1)
                .limit(pageCount)
                .parallel()
                .map(pageIndex -> list.stream()
                        .skip(pageIndex * pageSize)
                        .limit(pageSize)
                        .collect(Collectors.toList()))
                .collect(Collectors.toList());
    }

    /**
     * 获取对象属性值获取对象
     *
     * @param list
     * @param function
     * @param value
     * @return E
     * @author zhengxin
     * @date 2020/9/8 14:21
     * @version: 1.0
     */
    public static <E> E getByKey(List<E> list, Function<E, String> function, String value) {
        if (Objects.isNull(list) || list.size() == 0) {
            return null;
        }

        return list.stream()
                .filter(item -> StringUtil.trimAndEquals(value, function.apply(item)))
                .findFirst().orElse(null);
    }

    /**
     * 获取最大对象
     *
     * @param list
     * @param function
     * @return E
     * @author zhengxin
     * @date 2020/9/9 9:30
     * @version: 1.0
     */
    public static <E> E max(List<E> list, Function<E, String> function) {
        if (Objects.isNull(list) || list.size() == 0) {
            return null;
        }

        return list.stream()
                .filter(item -> StringUtils.isNotBlank(function.apply(item)))
                .max((e1, e2) -> function.apply(e1).compareTo(function.apply(e2)))
                .orElse(list.get(0));
    }





}
